
#include <gfx/iindexbuffer.h>
#include <gfx/ivertexbuffer.h>
#include <gfx/ivertexdeclaration.h>
#include <physics/physicsshapegenerator.h>

cmPhysicsShapeGenerator::cmPhysicsShapeGenerator()
{
}


btTriangleMeshShape*cmPhysicsShapeGenerator::CreateTriMeshShape(ceMesh *mesh)
{
  iVertexBuffer* vb = mesh->GetVertices();
  iIndexBuffer* ib = mesh->GetIndices();
  iVertexDeclaration* vd = mesh->GetVertexDeclration();

  static ceProgramParameterName positionName (PPB_Position0);
  const ceVertexElement* element = vd->GetElement (positionName, 0);
  if (element->Size != 3)
    {
      return 0;
    }

  char *vbData = 0;
  if (!vb->Lock(element->Offset, (void**)&vbData, BAM_Read))
    {
      return 0;
    }

  char *ibData = 0;
  if (!ib->Lock(0, (void**)&ibData, BAM_Read))
    {
      vb->Unlock();
      return 0;
    }

  btTriangleMesh* triMesh = new btTriangleMesh (true, true);

#define BTCEVECTOR3(v) btVector3 (v->x, v->y, v->z)
  if (mesh->Is32BitIndices())
    {
      for (unsigned i=0; i<mesh->GetNumberOfTrigons(); i++)
        {
          unsigned i0 = reinterpret_cast<unsigned*>(ibData)[i*3+0];
          unsigned i1 = reinterpret_cast<unsigned*>(ibData)[i*3+1];
          unsigned i2 = reinterpret_cast<unsigned*>(ibData)[i*3+2];

          ceVector3f* v0 = reinterpret_cast<ceVector3f*>(&vbData[i0 * element->Stride]);
          ceVector3f* v1 = reinterpret_cast<ceVector3f*>(&vbData[i1 * element->Stride]);
          ceVector3f* v2 = reinterpret_cast<ceVector3f*>(&vbData[i2 * element->Stride]);

          triMesh->addTriangle(
                BTCEVECTOR3(v0),
                BTCEVECTOR3(v1),
                BTCEVECTOR3(v2),
                true
                );
        }
    }
  else
    {
      for (unsigned i=0; i<mesh->GetNumberOfTrigons(); i++)
        {
          unsigned short i0 = reinterpret_cast<unsigned short*>(ibData)[i*3+0];
          unsigned short i1 = reinterpret_cast<unsigned short*>(ibData)[i*3+1];
          unsigned short i2 = reinterpret_cast<unsigned short*>(ibData)[i*3+2];

          ceVector3f* v0 = reinterpret_cast<ceVector3f*>(&vbData[i0 * element->Stride]);
          ceVector3f* v1 = reinterpret_cast<ceVector3f*>(&vbData[i1 * element->Stride]);
          ceVector3f* v2 = reinterpret_cast<ceVector3f*>(&vbData[i2 * element->Stride]);

          triMesh->addTriangle(
                BTCEVECTOR3(v0),
                BTCEVECTOR3(v1),
                BTCEVECTOR3(v2),
                true
                );
        }
    }


#undef BTCEVECTOR3

  vb->Unlock();
  ib->Unlock();

  return new btBvhTriangleMeshShape (triMesh, false, true);
}
